package utils;

import ftp.FtpConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;

import java.io.*;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author likai
 * @Date 2018/09/06
 */
public class ParseTradeFile {
    private static Logger logger = LoggerFactory.getLogger(ParseTradeFile.class);
    private ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
    private JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");
    /**
     * 更新普通二维码的乘车状态，乘车后，乘车状态为0
     */
    private final String updateSql = "update air_ride_qr_code set ride_status = ?, machine_number = ? where id = ? and ride_type = 1";

    /**
     * M1记录插入
     */
    private final String insertSql = "insert into air_ride_qr_code (ride_type, machine_number, order_number,ride_date, create_date, del_flag) values (0, ? , ?, ?, ?, 0)";

    /**
     * 插入特殊二维码的记录，便于统计
     */
    private final String insertQrCodeSql = "INSERT INTO air_ride_qr_code_special ( ride_date, machine_number, ride_no, qr_code_id, del_flag ) VALUES (?, ?, ?, ?, 0)";

    /**
     * 保存普通二维码的记录
     */
    private final String insertQrCodeHistorySql = "INSERT INTO air_ride_qr_code_history ( ride_date, machine_number, ride_no, qr_code_id, del_flag) VALUES (?, ?, ?, ?, 0)";

    /**
     * 目前的设备编号
     */
    private String currentDevice;

    public static void main(String[] args) throws IOException {
        String path = "D:\\ftpserver\\src\\main\\java\\utils\\003030303035-20181111110600.312";
        ParseTradeFile parseTradeFile = new ParseTradeFile();

        parseTradeFile.parseFile("003030303035-20181111110600.312", path, "batch");
    }

    /**
     * @param fileName 文件名
     * @param realPath 文件绝对路径
     * @param mode     模式，normal 或 batch
     */
    public void parseFile(String fileName, String realPath, String mode) {
        this.currentDevice = extractDevice(fileName);
        InputStream fileInputStream;
        try {
            fileInputStream = new FileInputStream(realPath);
            if ("normal".equals(mode)) {
                parseFile(fileInputStream);
            } else if ("batch".equals(mode)) {
                parseFileBatch(fileInputStream);
            } else {
                logger.info("mode 错误，只能为normal 和 batch");
            }
            fileInputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理文件，普通模式，一条一条的进行更新
     * 实际用的是batch模式
     *
     * @param fileInputStream
     */
    public void parseFile(InputStream fileInputStream) {
        try {
            TradeHeader tradeHeader = new TradeHeader();
            tradeHeader.setFile(fileInputStream);
            tradeHeader.parse();
            for (int i = 0; i < tradeHeader.getRecordNumber(); i++) {
                /**
                 * 读取交易类型
                 * 0x3C    航展M1卡
                 * 0x3D    航展二维码
                 */
                int tradeType = fileInputStream.read();
                if (tradeType == 0x3c) {
                    M1TradeBody m1TradeBody = new M1TradeBody(fileInputStream);
                    int a = 1;
                } else if (tradeType == 0x3d) {
                    QRCodeTradeBody qrCodeTradeBody = new QRCodeTradeBody(fileInputStream);
                    int rows = jdbcTemplate.update(updateSql, new Object[]{0, qrCodeTradeBody.getQRCodeInformationId()});
                    logger.info(qrCodeTradeBody.getQRCodeInformationId() + "   已被修改");
                    logger.info(rows + "行已修改 ");
                } else {
                    logger.info("未知的交易类型");
                    break;
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理文件，批处理模式，批次处理。提高性能
     *
     * @param fileInputStream
     */
    public void parseFileBatch(InputStream fileInputStream) {
        List<QRCodeTradeBody> qrCodeTradeBodies = new ArrayList<>(16);
        /**
         * 通用的二维码乘车记录
         */
        List<QRCodeTradeBody> specialQrCodeTradeList = new ArrayList<>(16);

        List<M1TradeBody> m1TradeBodies = new ArrayList<>(16);

        try {
            TradeHeader tradeHeader = new TradeHeader();
            tradeHeader.setFile(fileInputStream);
            tradeHeader.parse();
            int recordNumber = tradeHeader.getRecordNumber();
            logger.info(recordNumber + "条记录被解析");
            for (int i = 0; i < recordNumber; i++) {
                /**
                 * 读取交易类型
                 * 0x3C    航展M1卡
                 * 0x3D    航展二维码
                 */
                int tradeType = fileInputStream.read();
                if (tradeType == 0x3c) {
                    M1TradeBody m1TradeBody = new M1TradeBody(fileInputStream);
                    m1TradeBodies.add(m1TradeBody);
                } else if (tradeType == 0x3d) {
                    QRCodeTradeBody qrCodeTradeBody = new QRCodeTradeBody(fileInputStream);
                    String qrId = qrCodeTradeBody.getQRCodeInformationId();
                    if(FtpConfig.SPECIAL_ID_LIST.contains(qrId)){
                        specialQrCodeTradeList.add(qrCodeTradeBody);
                    }else{
                        qrCodeTradeBodies.add(qrCodeTradeBody);
                    }
                } else {
                    logger.info("未知的交易类型");
                    break;
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        /**
         * 批处理插入M1记录
         */
        batchInsert(m1TradeBodies);
        /**
         * 批处理更新二维码
         */
        batchUpdate(qrCodeTradeBodies);
        /**
         * 批处理插入特殊二维码
         */
        batchInsertQrCode(specialQrCodeTradeList);
    }

    private void batchInsertQrCode(List<QRCodeTradeBody> qrCodeTradeBodies) {
        logger.info("处理特殊二维码记录");
        logger.info("总共的条数是: " + qrCodeTradeBodies.size());
        int[] updateCounts = jdbcTemplate.batchUpdate(
                insertQrCodeSql,
                new BatchPreparedStatementSetter() {
                    @Override
                    public void setValues(PreparedStatement ps, int i) throws SQLException {
                        QRCodeTradeBody qr = qrCodeTradeBodies.get(i);
                        LocalDateTime dt = LocalDateTime.of(qr.getGatherDate(), qr.getGatherTime());
                        ps.setString(1, dt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss")));
                        ps.setString(2, currentDevice);

                        ps.setInt(3, qr.getPassengerNumber());

                        String id = qr.getQRCodeInformationId();
                        logger.info("特殊二维码id为:" + id);
                        ps.setString(4, id);
                    }

                    @Override
                    public int getBatchSize() {
                        return qrCodeTradeBodies.size();
                    }
                });
        logger.info(Arrays.toString(updateCounts));
    }

    private void batchInsert(List<M1TradeBody> m1TradeBodies) {
        logger.info("处理M1记录");
        logger.info("总共的条数是: " + m1TradeBodies.size());
        int[] InsertCounts = jdbcTemplate.batchUpdate(
                insertSql,
                new BatchPreparedStatementSetter() {
                    @Override
                    public void setValues(PreparedStatement ps, int i) throws SQLException {
                        M1TradeBody m1TradeBody = m1TradeBodies.get(i);
                        ps.setString(1, currentDevice);
                        String applicationCardNumber = m1TradeBodies.get(i).getApplicationCardNumber();
                        logger.info("应用卡号:"+applicationCardNumber);
                        ps.setString(2, applicationCardNumber);
                        LocalDateTime dt = LocalDateTime.of(m1TradeBody.getGatherDate(), m1TradeBody.getGatherTime());
                        ps.setString(3, dt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss")));
                        ps.setTimestamp(4, new Timestamp(System.currentTimeMillis()));
                    }

                    @Override
                    public int getBatchSize() {
                        return m1TradeBodies.size();
                    }
                });
        logger.info(Arrays.toString(InsertCounts));
    }

    public void batchUpdate(List<QRCodeTradeBody> qrCodeTradeBodies) {
        logger.info("处理二维码记录");
        logger.info("总共的条数是: " + qrCodeTradeBodies.size());
        int[] updateCounts = jdbcTemplate.batchUpdate(
                updateSql,
                new BatchPreparedStatementSetter() {
                    @Override
                    public void setValues(PreparedStatement ps, int i) throws SQLException {
                        ps.setInt(1, 0);
                        ps.setString(2, currentDevice);
                        String id = qrCodeTradeBodies.get(i).getQRCodeInformationId();
                        logger.info("二维码id为:" + id);
                        ps.setString(3, id);
                    }

                    @Override
                    public int getBatchSize() {
                        return qrCodeTradeBodies.size();
                    }
                });
        logger.info(Arrays.toString(updateCounts));

        /*
        保存二维码扫码记录
         */
        int[] historyCounts = jdbcTemplate.batchUpdate(
                insertQrCodeHistorySql,
                new BatchPreparedStatementSetter() {
                    @Override
                    public void setValues(PreparedStatement ps, int i) throws SQLException {
                        QRCodeTradeBody qr = qrCodeTradeBodies.get(i);
                        LocalDateTime dt = LocalDateTime.of(qr.getGatherDate(), qr.getGatherTime());
                        ps.setString(1, dt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss")));
                        ps.setString(2, currentDevice);
                        String id = qr.getQRCodeInformationId();
                        logger.info("保存历史的二维码id为:" + id);
                        ps.setInt(3, qr.getPassengerNumber());
                        ps.setString(4, id);
                    }

                    @Override
                    public int getBatchSize() {
                        return qrCodeTradeBodies.size();
                    }
                });
        logger.info(Arrays.toString(historyCounts));
    }


    public void parseFile(byte[] bytes) {
        InputStream fileInputStream = new ByteArrayInputStream(bytes);
        parseFile(fileInputStream);
    }

    private String extractDevice(String fileName) {
        String data = fileName.substring(0, fileName.indexOf('-'));
        return StringToHex.convert(data);
    }

    public String getCurrentDevice() {
        return currentDevice;
    }

    public void setCurrentDevice(String currentDevice) {
        this.currentDevice = currentDevice;
    }
}
